/**
 ******************************************************************************
 * @file    bl702_uart.c
 * @version V1.0
 * @date
 * @brief   This file is the standard driver c file
 ******************************************************************************
 * @attention
 *
 * <h2><center>&copy; COPYRIGHT(c) 2020 Bouffalo Lab</center></h2>
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *   1. Redistributions of source code must retain the above copyright notice,
 *      this list of conditions and the following disclaimer.
 *   2. Redistributions in binary form must reproduce the above copyright notice,
 *      this list of conditions and the following disclaimer in the documentation
 *      and/or other materials provided with the distribution.
 *   3. Neither the name of Bouffalo Lab nor the names of its contributors
 *      may be used to endorse or promote products derived from this software
 *      without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 ******************************************************************************
 */

#include "bl702_uart.h"
#include "bl702_glb.h"

/** @addtogroup  BL702_Peripheral_Driver
 *  @{
 */

/** @addtogroup  UART
 *  @{
 */

/** @defgroup  UART_Private_Macros
 *  @{
 */
#define UART_TX_TIMEOUT_COUNT (160 * 1000)

/*@} end of group UART_Private_Macros */

/** @defgroup  UART_Private_Types
 *  @{
 */

/*@} end of group UART_Private_Types */

/** @defgroup  UART_Private_Variables
 *  @{
 */
static const uint32_t    uartAddr[2]                     = {UART0_BASE, UART1_BASE};
static intCallback_Type *uartIntCbfArra[2][UART_INT_ALL] = {{NULL}, {NULL}};

/*@} end of group UART_Private_Variables */

/** @defgroup  UART_Global_Variables
 *  @{
 */

/*@} end of group UART_Global_Variables */

/** @defgroup  UART_Private_Fun_Declaration
 *  @{
 */
#ifndef BFLB_USE_HAL_DRIVER
static void UART_IntHandler(UART_ID_Type uartId);
#endif

/*@} end of group UART_Private_Fun_Declaration */

/** @defgroup  UART_Private_Functions
 *  @{
 */

/****************************************************************************/ /**
                                                                                * @brief  UART interrupt common handler function
                                                                                *
                                                                                * @param  uartId: UART ID type
                                                                                *
                                                                                * @return None
                                                                                *
                                                                                *******************************************************************************/
#ifndef BFLB_USE_HAL_DRIVER
static void UART_IntHandler(UART_ID_Type uartId) {
  uint32_t tmpVal  = 0;
  uint32_t maskVal = 0;
  uint32_t UARTx   = uartAddr[uartId];

  tmpVal  = BL_RD_REG(UARTx, UART_INT_STS);
  maskVal = BL_RD_REG(UARTx, UART_INT_MASK);

  /* Length of uart tx data transfer arrived interrupt */
  if (BL_IS_REG_BIT_SET(tmpVal, UART_UTX_END_INT) && !BL_IS_REG_BIT_SET(maskVal, UART_CR_UTX_END_MASK)) {
    BL_WR_REG(UARTx, UART_INT_CLEAR, 0x1);

    if (uartIntCbfArra[uartId][UART_INT_TX_END] != NULL) {
      uartIntCbfArra[uartId][UART_INT_TX_END]();
    }
  }

  /* Length of uart rx data transfer arrived interrupt */
  if (BL_IS_REG_BIT_SET(tmpVal, UART_URX_END_INT) && !BL_IS_REG_BIT_SET(maskVal, UART_CR_URX_END_MASK)) {
    BL_WR_REG(UARTx, UART_INT_CLEAR, 0x2);

    if (uartIntCbfArra[uartId][UART_INT_RX_END] != NULL) {
      uartIntCbfArra[uartId][UART_INT_RX_END]();
    }
  }

  /* Tx fifo ready interrupt,auto-cleared when data is pushed */
  if (BL_IS_REG_BIT_SET(tmpVal, UART_UTX_FIFO_INT) && !BL_IS_REG_BIT_SET(maskVal, UART_CR_UTX_FIFO_MASK)) {
    if (uartIntCbfArra[uartId][UART_INT_TX_FIFO_REQ] != NULL) {
      uartIntCbfArra[uartId][UART_INT_TX_FIFO_REQ]();
    }
  }

  /* Rx fifo ready interrupt,auto-cleared when data is popped */
  if (BL_IS_REG_BIT_SET(tmpVal, UART_URX_FIFO_INT) && !BL_IS_REG_BIT_SET(maskVal, UART_CR_URX_FIFO_MASK)) {
    if (uartIntCbfArra[uartId][UART_INT_RX_FIFO_REQ] != NULL) {
      uartIntCbfArra[uartId][UART_INT_RX_FIFO_REQ]();
    }
  }

  /* Rx time-out interrupt */
  if (BL_IS_REG_BIT_SET(tmpVal, UART_URX_RTO_INT) && !BL_IS_REG_BIT_SET(maskVal, UART_CR_URX_RTO_MASK)) {
    BL_WR_REG(UARTx, UART_INT_CLEAR, 0x10);

    if (uartIntCbfArra[uartId][UART_INT_RTO] != NULL) {
      uartIntCbfArra[uartId][UART_INT_RTO]();
    }
  }

  /* Rx parity check error interrupt */
  if (BL_IS_REG_BIT_SET(tmpVal, UART_URX_PCE_INT) && !BL_IS_REG_BIT_SET(maskVal, UART_CR_URX_PCE_MASK)) {
    BL_WR_REG(UARTx, UART_INT_CLEAR, 0x20);

    if (uartIntCbfArra[uartId][UART_INT_PCE] != NULL) {
      uartIntCbfArra[uartId][UART_INT_PCE]();
    }
  }

  /* Tx fifo overflow/underflow error interrupt */
  if (BL_IS_REG_BIT_SET(tmpVal, UART_UTX_FER_INT) && !BL_IS_REG_BIT_SET(maskVal, UART_CR_UTX_FER_MASK)) {
    if (uartIntCbfArra[uartId][UART_INT_TX_FER] != NULL) {
      uartIntCbfArra[uartId][UART_INT_TX_FER]();
    }
  }

  /* Rx fifo overflow/underflow error interrupt */
  if (BL_IS_REG_BIT_SET(tmpVal, UART_URX_FER_INT) && !BL_IS_REG_BIT_SET(maskVal, UART_CR_URX_FER_MASK)) {
    if (uartIntCbfArra[uartId][UART_INT_RX_FER] != NULL) {
      uartIntCbfArra[uartId][UART_INT_RX_FER]();
    }
  }

  /* Rx lin mode sync field error interrupt */
  if (BL_IS_REG_BIT_SET(tmpVal, UART_URX_LSE_INT) && !BL_IS_REG_BIT_SET(maskVal, UART_CR_URX_LSE_MASK)) {
    BL_WR_REG(UARTx, UART_INT_CLEAR, 0x100);

    if (uartIntCbfArra[uartId][UART_INT_LSE] != NULL) {
      uartIntCbfArra[uartId][UART_INT_LSE]();
    }
  }
}
#endif

/*@} end of group UART_Private_Functions */

/** @defgroup  UART_Public_Functions
 *  @{
 */

/****************************************************************************/ /**
                                                                                * @brief  UART initialization function
                                                                                *
                                                                                * @param  uartId: UART ID type
                                                                                * @param  uartCfg: UART configuration structure pointer
                                                                                *
                                                                                * @return SUCCESS
                                                                                *
                                                                                *******************************************************************************/
BL_Err_Type UART_Init(UART_ID_Type uartId, UART_CFG_Type *uartCfg) {
  uint32_t tmpValTxCfg     = 0;
  uint32_t tmpValRxCfg     = 0;
  uint32_t fraction        = 0;
  uint32_t baudRateDivisor = 0;
  uint32_t UARTx           = uartAddr[uartId];

  /* Check the parameters */
  CHECK_PARAM(IS_UART_ID_TYPE(uartId));
  CHECK_PARAM(IS_UART_PARITY_TYPE(uartCfg->parity));
  CHECK_PARAM(IS_UART_DATABITS_TYPE(uartCfg->dataBits));
  CHECK_PARAM(IS_UART_STOPBITS_TYPE(uartCfg->stopBits));
  CHECK_PARAM(IS_UART_BYTEBITINVERSE_TYPE(uartCfg->byteBitInverse));

  /* Cal the baud rate divisor */
  fraction        = uartCfg->uartClk * 10 / uartCfg->baudRate % 10;
  baudRateDivisor = uartCfg->uartClk / uartCfg->baudRate;

  if (fraction >= 5) {
    ++baudRateDivisor;
  }

  /* Set the baud rate register value */
  BL_WR_REG(UARTx, UART_BIT_PRD, ((baudRateDivisor - 1) << 0x10) | ((baudRateDivisor - 1) & 0xFFFF));

  /* Configure parity type */
  tmpValTxCfg = BL_RD_REG(UARTx, UART_UTX_CONFIG);
  tmpValRxCfg = BL_RD_REG(UARTx, UART_URX_CONFIG);

  switch (uartCfg->parity) {
  case UART_PARITY_NONE:
    tmpValTxCfg = BL_CLR_REG_BIT(tmpValTxCfg, UART_CR_UTX_PRT_EN);
    tmpValRxCfg = BL_CLR_REG_BIT(tmpValRxCfg, UART_CR_URX_PRT_EN);
    break;

  case UART_PARITY_ODD:
    tmpValTxCfg = BL_SET_REG_BIT(tmpValTxCfg, UART_CR_UTX_PRT_EN);
    tmpValTxCfg = BL_SET_REG_BIT(tmpValTxCfg, UART_CR_UTX_PRT_SEL);
    tmpValRxCfg = BL_SET_REG_BIT(tmpValRxCfg, UART_CR_URX_PRT_EN);
    tmpValRxCfg = BL_SET_REG_BIT(tmpValRxCfg, UART_CR_URX_PRT_SEL);
    break;

  case UART_PARITY_EVEN:
    tmpValTxCfg = BL_SET_REG_BIT(tmpValTxCfg, UART_CR_UTX_PRT_EN);
    tmpValTxCfg = BL_CLR_REG_BIT(tmpValTxCfg, UART_CR_UTX_PRT_SEL);
    tmpValRxCfg = BL_SET_REG_BIT(tmpValRxCfg, UART_CR_URX_PRT_EN);
    tmpValRxCfg = BL_CLR_REG_BIT(tmpValRxCfg, UART_CR_URX_PRT_SEL);
    break;

  default:
    break;
  }

  /* Configure data bits */
  tmpValTxCfg = BL_SET_REG_BITS_VAL(tmpValTxCfg, UART_CR_UTX_BIT_CNT_D, (uartCfg->dataBits + 4));
  tmpValRxCfg = BL_SET_REG_BITS_VAL(tmpValRxCfg, UART_CR_URX_BIT_CNT_D, (uartCfg->dataBits + 4));

  /* Configure tx stop bits */
  tmpValTxCfg = BL_SET_REG_BITS_VAL(tmpValTxCfg, UART_CR_UTX_BIT_CNT_P, uartCfg->stopBits);

  /* Configure tx cts flow control function */
  tmpValTxCfg = BL_SET_REG_BITS_VAL(tmpValTxCfg, UART_CR_UTX_CTS_EN, uartCfg->ctsFlowControl);

  /* Configure rx input de-glitch function */
  tmpValRxCfg = BL_SET_REG_BITS_VAL(tmpValRxCfg, UART_CR_URX_DEG_EN, uartCfg->rxDeglitch);

  /* Configure tx lin mode function */
  tmpValTxCfg = BL_SET_REG_BITS_VAL(tmpValTxCfg, UART_CR_UTX_LIN_EN, uartCfg->txLinMode);

  /* Configure rx lin mode function */
  tmpValRxCfg = BL_SET_REG_BITS_VAL(tmpValRxCfg, UART_CR_URX_LIN_EN, uartCfg->rxLinMode);

  /* Set tx break bit count for lin protocol */
  tmpValTxCfg = BL_SET_REG_BITS_VAL(tmpValTxCfg, UART_CR_UTX_BIT_CNT_B, uartCfg->txBreakBitCnt);

  /* Write back */
  BL_WR_REG(UARTx, UART_UTX_CONFIG, tmpValTxCfg);
  BL_WR_REG(UARTx, UART_URX_CONFIG, tmpValRxCfg);

  /* Configure LSB-first or MSB-first */
  tmpValTxCfg = BL_RD_REG(UARTx, UART_DATA_CONFIG);

  if (UART_MSB_FIRST == uartCfg->byteBitInverse) {
    tmpValTxCfg = BL_SET_REG_BIT(tmpValTxCfg, UART_CR_UART_BIT_INV);
  } else {
    tmpValTxCfg = BL_CLR_REG_BIT(tmpValTxCfg, UART_CR_UART_BIT_INV);
  }

  BL_WR_REG(UARTx, UART_DATA_CONFIG, tmpValTxCfg);

  tmpValTxCfg = BL_RD_REG(UARTx, UART_SW_MODE);
  /* Configure rx rts output SW control mode */
  tmpValTxCfg = BL_SET_REG_BITS_VAL(tmpValTxCfg, UART_CR_URX_RTS_SW_MODE, uartCfg->rtsSoftwareControl);
  /* Configure tx output SW control mode */
  tmpValTxCfg = BL_SET_REG_BITS_VAL(tmpValTxCfg, UART_CR_UTX_TXD_SW_MODE, uartCfg->txSoftwareControl);
  BL_WR_REG(UARTx, UART_SW_MODE, tmpValTxCfg);

#ifndef BFLB_USE_HAL_DRIVER
  Interrupt_Handler_Register(UART0_IRQn, UART0_IRQHandler);
  Interrupt_Handler_Register(UART1_IRQn, UART1_IRQHandler);
#endif
  return SUCCESS;
}

/****************************************************************************/ /**
                                                                                * @brief  UART set default value of all registers function
                                                                                *
                                                                                * @param  uartId: UART ID type
                                                                                *
                                                                                * @return SUCCESS
                                                                                *
                                                                                *******************************************************************************/
BL_Err_Type UART_DeInit(UART_ID_Type uartId) {
  if (UART0_ID == uartId) {
    GLB_AHB_Slave1_Reset(BL_AHB_SLAVE1_UART0);
  } else if (UART1_ID == uartId) {
    GLB_AHB_Slave1_Reset(BL_AHB_SLAVE1_UART1);
  }

  return SUCCESS;
}

/****************************************************************************/ /**
                                                                                * @brief  UART configure fifo function
                                                                                *
                                                                                * @param  uartId: UART ID type
                                                                                * @param  fifoCfg: FIFO configuration structure pointer
                                                                                *
                                                                                * @return SUCCESS
                                                                                *
                                                                                *******************************************************************************/
BL_Err_Type UART_FifoConfig(UART_ID_Type uartId, UART_FifoCfg_Type *fifoCfg) {
  uint32_t tmpVal = 0;
  uint32_t UARTx  = uartAddr[uartId];

  /* Check the parameters */
  CHECK_PARAM(IS_UART_ID_TYPE(uartId));

  /* Deal with uart fifo configure register */
  tmpVal = BL_RD_REG(UARTx, UART_FIFO_CONFIG_1);
  /* Configure dma tx fifo threshold */
  tmpVal = BL_SET_REG_BITS_VAL(tmpVal, UART_TX_FIFO_TH, fifoCfg->txFifoDmaThreshold);
  /* Configure dma rx fifo threshold */
  tmpVal = BL_SET_REG_BITS_VAL(tmpVal, UART_RX_FIFO_TH, fifoCfg->rxFifoDmaThreshold);
  /* Write back */
  BL_WR_REG(UARTx, UART_FIFO_CONFIG_1, tmpVal);

  /* Enable or disable uart fifo dma function */
  tmpVal = BL_RD_REG(UARTx, UART_FIFO_CONFIG_0);

  if (ENABLE == fifoCfg->txFifoDmaEnable) {
    tmpVal = BL_SET_REG_BIT(tmpVal, UART_DMA_TX_EN);
  } else {
    tmpVal = BL_CLR_REG_BIT(tmpVal, UART_DMA_TX_EN);
  }

  if (ENABLE == fifoCfg->rxFifoDmaEnable) {
    tmpVal = BL_SET_REG_BIT(tmpVal, UART_DMA_RX_EN);
  } else {
    tmpVal = BL_CLR_REG_BIT(tmpVal, UART_DMA_RX_EN);
  }

  BL_WR_REG(UARTx, UART_FIFO_CONFIG_0, tmpVal);

  return SUCCESS;
}

/****************************************************************************/ /**
                                                                                * @brief  UART configure infra function
                                                                                *
                                                                                * @param  uartId: UART ID type
                                                                                * @param  irCfg: IR configuration structure pointer
                                                                                *
                                                                                * @return SUCCESS
                                                                                *
                                                                                *******************************************************************************/
BL_Err_Type UART_IrConfig(UART_ID_Type uartId, UART_IrCfg_Type *irCfg) {
  uint32_t tmpVal = 0;
  uint32_t UARTx  = uartAddr[uartId];

  /* Check the parameters */
  CHECK_PARAM(IS_UART_ID_TYPE(uartId));

  /* Configure tx ir mode */
  tmpVal = BL_RD_REG(UARTx, UART_UTX_CONFIG);

  if (ENABLE == irCfg->txIrEnable) {
    tmpVal = BL_SET_REG_BIT(tmpVal, UART_CR_UTX_IR_EN);
  } else {
    tmpVal = BL_CLR_REG_BIT(tmpVal, UART_CR_UTX_IR_EN);
  }

  if (ENABLE == irCfg->txIrInverse) {
    tmpVal = BL_SET_REG_BIT(tmpVal, UART_CR_UTX_IR_INV);
  } else {
    tmpVal = BL_CLR_REG_BIT(tmpVal, UART_CR_UTX_IR_INV);
  }

  BL_WR_REG(UARTx, UART_UTX_CONFIG, tmpVal);

  /* Configure rx ir mode */
  tmpVal = BL_RD_REG(UARTx, UART_URX_CONFIG);

  if (ENABLE == irCfg->rxIrEnable) {
    tmpVal = BL_SET_REG_BIT(tmpVal, UART_CR_URX_IR_EN);
  } else {
    tmpVal = BL_CLR_REG_BIT(tmpVal, UART_CR_URX_IR_EN);
  }

  if (ENABLE == irCfg->rxIrInverse) {
    tmpVal = BL_SET_REG_BIT(tmpVal, UART_CR_URX_IR_INV);
  } else {
    tmpVal = BL_CLR_REG_BIT(tmpVal, UART_CR_URX_IR_INV);
  }

  BL_WR_REG(UARTx, UART_URX_CONFIG, tmpVal);

  /* Configure tx ir pulse start and stop position */
  BL_WR_REG(UARTx, UART_UTX_IR_POSITION, irCfg->txIrPulseStop << 0x10 | irCfg->txIrPulseStart);

  /* Configure rx ir pulse start position */
  BL_WR_REG(UARTx, UART_URX_IR_POSITION, irCfg->rxIrPulseStart);

  return SUCCESS;
}

/****************************************************************************/ /**
                                                                                * @brief  Enable UART
                                                                                *
                                                                                * @param  uartId: UART ID type
                                                                                * @param  direct: UART direction type
                                                                                *
                                                                                * @return SUCCESS
                                                                                *
                                                                                *******************************************************************************/
BL_Err_Type UART_Enable(UART_ID_Type uartId, UART_Direction_Type direct) {
  uint32_t tmpVal = 0;
  uint32_t UARTx  = uartAddr[uartId];

  /* Check the parameters */
  CHECK_PARAM(IS_UART_ID_TYPE(uartId));
  CHECK_PARAM(IS_UART_DIRECTION_TYPE(direct));

  if (direct == UART_TX || direct == UART_TXRX) {
    /* Enable UART tx unit */
    tmpVal = BL_RD_REG(UARTx, UART_UTX_CONFIG);
    BL_WR_REG(UARTx, UART_UTX_CONFIG, BL_SET_REG_BIT(tmpVal, UART_CR_UTX_EN));
  }

  if (direct == UART_RX || direct == UART_TXRX) {
    /* Enable UART rx unit */
    tmpVal = BL_RD_REG(UARTx, UART_URX_CONFIG);
    BL_WR_REG(UARTx, UART_URX_CONFIG, BL_SET_REG_BIT(tmpVal, UART_CR_URX_EN));
  }

  return SUCCESS;
}

/****************************************************************************/ /**
                                                                                * @brief  Disable UART
                                                                                *
                                                                                * @param  uartId: UART ID type
                                                                                * @param  direct: UART direction type
                                                                                *
                                                                                * @return SUCCESS
                                                                                *
                                                                                *******************************************************************************/
BL_Err_Type UART_Disable(UART_ID_Type uartId, UART_Direction_Type direct) {
  uint32_t tmpVal = 0;
  uint32_t UARTx  = uartAddr[uartId];

  /* Check the parameters */
  CHECK_PARAM(IS_UART_ID_TYPE(uartId));
  CHECK_PARAM(IS_UART_DIRECTION_TYPE(direct));

  if (direct == UART_TX || direct == UART_TXRX) {
    /* Disable UART tx unit */
    tmpVal = BL_RD_REG(UARTx, UART_UTX_CONFIG);
    BL_WR_REG(UARTx, UART_UTX_CONFIG, BL_CLR_REG_BIT(tmpVal, UART_CR_UTX_EN));
  }

  if (direct == UART_RX || direct == UART_TXRX) {
    /* Disable UART rx unit */
    tmpVal = BL_RD_REG(UARTx, UART_URX_CONFIG);
    BL_WR_REG(UARTx, UART_URX_CONFIG, BL_CLR_REG_BIT(tmpVal, UART_CR_URX_EN));
  }

  return SUCCESS;
}

/****************************************************************************/ /**
                                                                                * @brief  UART set length of tx data transfer,tx end interrupt will assert when this length is
                                                                                *         reached
                                                                                *
                                                                                * @param  uartId: UART ID type
                                                                                * @param  length: Length of data (unit:character/byte)
                                                                                *
                                                                                * @return SUCCESS
                                                                                *
                                                                                *******************************************************************************/
BL_Err_Type UART_SetTxDataLength(UART_ID_Type uartId, uint16_t length) {
  uint32_t tmpVal = 0;
  uint32_t UARTx  = uartAddr[uartId];

  /* Check the parameters */
  CHECK_PARAM(IS_UART_ID_TYPE(uartId));

  /* Set length */
  tmpVal = BL_RD_REG(UARTx, UART_UTX_CONFIG);
  BL_WR_REG(UARTx, UART_UTX_CONFIG, BL_SET_REG_BITS_VAL(tmpVal, UART_CR_UTX_LEN, length - 1));

  return SUCCESS;
}

/****************************************************************************/ /**
                                                                                * @brief  UART set length of rx data transfer,rx end interrupt will assert when this length is
                                                                                *         reached
                                                                                *
                                                                                * @param  uartId: UART ID type
                                                                                * @param  length: Length of data (unit:character/byte)
                                                                                *
                                                                                * @return SUCCESS
                                                                                *
                                                                                *******************************************************************************/
BL_Err_Type UART_SetRxDataLength(UART_ID_Type uartId, uint16_t length) {
  uint32_t tmpVal = 0;
  uint32_t UARTx  = uartAddr[uartId];

  /* Check the parameters */
  CHECK_PARAM(IS_UART_ID_TYPE(uartId));

  /* Set length */
  tmpVal = BL_RD_REG(UARTx, UART_URX_CONFIG);
  BL_WR_REG(UARTx, UART_URX_CONFIG, BL_SET_REG_BITS_VAL(tmpVal, UART_CR_URX_LEN, length - 1));

  return SUCCESS;
}

/****************************************************************************/ /**
                                                                                * @brief  UART set rx time-out value for triggering RTO interrupt
                                                                                *
                                                                                * @param  uartId: UART ID type
                                                                                * @param  time: Time-out value (unit:bit time)
                                                                                *
                                                                                * @return SUCCESS
                                                                                *
                                                                                *******************************************************************************/
BL_Err_Type UART_SetRxTimeoutValue(UART_ID_Type uartId, uint8_t time) {
  uint32_t UARTx = uartAddr[uartId];
  uint32_t tmpVal;

  /* Check the parameters */
  CHECK_PARAM(IS_UART_ID_TYPE(uartId));

  /* Set time-out value */
  tmpVal = BL_RD_REG(UARTx, UART_URX_RTO_TIMER);
  tmpVal = BL_SET_REG_BITS_VAL(tmpVal, UART_CR_URX_RTO_VALUE, time - 1);
  BL_WR_REG(UARTx, UART_URX_RTO_TIMER, tmpVal);

  return SUCCESS;
}

/****************************************************************************/ /**
                                                                                * @brief  UART set de-glitch function cycle count value
                                                                                *
                                                                                * @param  uartId: UART ID type
                                                                                * @param  deglitchCnt: De-glitch function cycle count
                                                                                *
                                                                                * @return SUCCESS
                                                                                *
                                                                                *******************************************************************************/
BL_Err_Type UART_SetDeglitchCount(UART_ID_Type uartId, uint8_t deglitchCnt) {
  uint32_t UARTx = uartAddr[uartId];
  uint32_t tmpVal;

  /* Check the parameters */
  CHECK_PARAM(IS_UART_ID_TYPE(uartId));

  /* Set count value */
  tmpVal = BL_RD_REG(UARTx, UART_URX_CONFIG);
  tmpVal = BL_SET_REG_BITS_VAL(tmpVal, UART_CR_URX_DEG_CNT, deglitchCnt);
  BL_WR_REG(UARTx, UART_URX_CONFIG, tmpVal);

  return SUCCESS;
}

/****************************************************************************/ /**
                                                                                * @brief  UART set tx and rx baudrate according to auto baudrate detection value
                                                                                *
                                                                                * @param  uartId: UART ID type
                                                                                * @param  autoBaudDet: Choose detection value using codeword 0x55 or start bit
                                                                                *
                                                                                * @return SUCCESS
                                                                                *
                                                                                *******************************************************************************/
BL_Err_Type UART_ApplyAbrResult(UART_ID_Type uartId, UART_AutoBaudDetection_Type autoBaudDet) {
  uint32_t UARTx = uartAddr[uartId];
  uint16_t tmpVal;

  /* Check the parameters */
  CHECK_PARAM(IS_UART_ID_TYPE(uartId));

  /* Get detection value */
  tmpVal = UART_GetAutoBaudCount(uartId, autoBaudDet);

  /* Set tx baudrate */
  BL_WR_REG(UARTx, UART_BIT_PRD, tmpVal << 0x10 | tmpVal);

  return SUCCESS;
}

/****************************************************************************/ /**
                                                                                * @brief  UART set rx rts output software control value
                                                                                *
                                                                                * @param  uartId: UART ID type
                                                                                *
                                                                                * @return SUCCESS
                                                                                *
                                                                                *******************************************************************************/
BL_Err_Type UART_SetRtsValue(UART_ID_Type uartId) {
  uint32_t UARTx = uartAddr[uartId];
  uint32_t tmpVal;

  /* Check the parameters */
  CHECK_PARAM(IS_UART_ID_TYPE(uartId));

  /* Rts set 1*/
  tmpVal = BL_RD_REG(UARTx, UART_SW_MODE);
  BL_WR_REG(UARTx, UART_SW_MODE, BL_SET_REG_BIT(tmpVal, UART_CR_URX_RTS_SW_VAL));

  return SUCCESS;
}

/****************************************************************************/ /**
                                                                                * @brief  UART clear rx rts output software control value
                                                                                *
                                                                                * @param  uartId: UART ID type
                                                                                *
                                                                                * @return SUCCESS
                                                                                *
                                                                                *******************************************************************************/
BL_Err_Type UART_ClrRtsValue(UART_ID_Type uartId) {
  uint32_t UARTx = uartAddr[uartId];
  uint32_t tmpVal;

  /* Check the parameters */
  CHECK_PARAM(IS_UART_ID_TYPE(uartId));

  /* Rts clear 0 */
  tmpVal = BL_RD_REG(UARTx, UART_SW_MODE);
  BL_WR_REG(UARTx, UART_SW_MODE, BL_CLR_REG_BIT(tmpVal, UART_CR_URX_RTS_SW_VAL));

  return SUCCESS;
}

/****************************************************************************/ /**
                                                                                * @brief  UART set tx output software control value
                                                                                *
                                                                                * @param  uartId: UART ID type
                                                                                *
                                                                                * @return SUCCESS
                                                                                *
                                                                                *******************************************************************************/
BL_Err_Type UART_SetTxValue(UART_ID_Type uartId) {
  uint32_t UARTx = uartAddr[uartId];
  uint32_t tmpVal;

  /* Check the parameters */
  CHECK_PARAM(IS_UART_ID_TYPE(uartId));

  /* Tx set 1*/
  tmpVal = BL_RD_REG(UARTx, UART_SW_MODE);
  BL_WR_REG(UARTx, UART_SW_MODE, BL_SET_REG_BIT(tmpVal, UART_CR_UTX_TXD_SW_VAL));

  return SUCCESS;
}

/****************************************************************************/ /**
                                                                                * @brief  UART clear tx output software control value
                                                                                *
                                                                                * @param  uartId: UART ID type
                                                                                *
                                                                                * @return SUCCESS
                                                                                *
                                                                                *******************************************************************************/
BL_Err_Type UART_ClrTxValue(UART_ID_Type uartId) {
  uint32_t UARTx = uartAddr[uartId];
  uint32_t tmpVal;

  /* Check the parameters */
  CHECK_PARAM(IS_UART_ID_TYPE(uartId));

  /* Rts clear 0 */
  tmpVal = BL_RD_REG(UARTx, UART_SW_MODE);
  BL_WR_REG(UARTx, UART_SW_MODE, BL_CLR_REG_BIT(tmpVal, UART_CR_UTX_TXD_SW_VAL));

  return SUCCESS;
}

/****************************************************************************/ /**
                                                                                * @brief  UART configure tx free run mode function
                                                                                *
                                                                                * @param  uartId: UART ID type
                                                                                * @param  txFreeRun: Enable or disable tx free run mode
                                                                                *
                                                                                * @return SUCCESS
                                                                                *
                                                                                *******************************************************************************/
BL_Err_Type UART_TxFreeRun(UART_ID_Type uartId, BL_Fun_Type txFreeRun) {
  uint32_t tmpVal = 0;
  uint32_t UARTx  = uartAddr[uartId];

  /* Check the parameters */
  CHECK_PARAM(IS_UART_ID_TYPE(uartId));

  /* Enable or disable tx free run mode */
  tmpVal = BL_RD_REG(UARTx, UART_UTX_CONFIG);

  if (ENABLE == txFreeRun) {
    BL_WR_REG(UARTx, UART_UTX_CONFIG, BL_SET_REG_BIT(tmpVal, UART_CR_UTX_FRM_EN));
  } else {
    BL_WR_REG(UARTx, UART_UTX_CONFIG, BL_CLR_REG_BIT(tmpVal, UART_CR_UTX_FRM_EN));
  }

  return SUCCESS;
}

/****************************************************************************/ /**
                                                                                * @brief  UART configure auto baud rate detection function
                                                                                *
                                                                                * @param  uartId: UART ID type
                                                                                * @param  autoBaud: Enable or disable auto function
                                                                                *
                                                                                * @return SUCCESS
                                                                                *
                                                                                *******************************************************************************/
BL_Err_Type UART_AutoBaudDetection(UART_ID_Type uartId, BL_Fun_Type autoBaud) {
  uint32_t tmpVal = 0;
  uint32_t UARTx  = uartAddr[uartId];

  /* Check the parameters */
  CHECK_PARAM(IS_UART_ID_TYPE(uartId));

  /* Enable or disable auto baud rate detection function */
  tmpVal = BL_RD_REG(UARTx, UART_URX_CONFIG);

  if (ENABLE == autoBaud) {
    BL_WR_REG(UARTx, UART_URX_CONFIG, BL_SET_REG_BIT(tmpVal, UART_CR_URX_ABR_EN));
  } else {
    BL_WR_REG(UARTx, UART_URX_CONFIG, BL_CLR_REG_BIT(tmpVal, UART_CR_URX_ABR_EN));
  }

  return SUCCESS;
}

/****************************************************************************/ /**
                                                                                * @brief  UART tx fifo clear
                                                                                *
                                                                                * @param  uartId: UART ID type
                                                                                *
                                                                                * @return SUCCESS
                                                                                *
                                                                                *******************************************************************************/
BL_Err_Type UART_TxFifoClear(UART_ID_Type uartId) {
  uint32_t tmpVal = 0;
  uint32_t UARTx  = uartAddr[uartId];

  /* Check the parameter */
  CHECK_PARAM(IS_UART_ID_TYPE(uartId));

  /* Clear tx fifo */
  tmpVal = BL_RD_REG(UARTx, UART_FIFO_CONFIG_0);
  BL_WR_REG(UARTx, UART_FIFO_CONFIG_0, BL_SET_REG_BIT(tmpVal, UART_TX_FIFO_CLR));

  return SUCCESS;
}

/****************************************************************************/ /**
                                                                                * @brief  UART rx fifo clear
                                                                                *
                                                                                * @param  uartId: UART ID type
                                                                                *
                                                                                * @return SUCCESS
                                                                                *
                                                                                *******************************************************************************/
BL_Err_Type UART_RxFifoClear(UART_ID_Type uartId) {
  uint32_t tmpVal = 0;
  uint32_t UARTx  = uartAddr[uartId];

  /* Check the parameter */
  CHECK_PARAM(IS_UART_ID_TYPE(uartId));

  /* Clear rx fifo */
  tmpVal = BL_RD_REG(UARTx, UART_FIFO_CONFIG_0);
  BL_WR_REG(UARTx, UART_FIFO_CONFIG_0, BL_SET_REG_BIT(tmpVal, UART_RX_FIFO_CLR));

  return SUCCESS;
}

/****************************************************************************/ /**
                                                                                * @brief  UART mask or unmask certain or all interrupt
                                                                                *
                                                                                * @param  uartId: UART ID type
                                                                                * @param  intType: UART interrupt type
                                                                                * @param  intMask: UART interrupt mask value( MASK:disbale interrupt,UNMASK:enable interrupt )
                                                                                *
                                                                                * @return SUCCESS
                                                                                *
                                                                                *******************************************************************************/
BL_Err_Type UART_IntMask(UART_ID_Type uartId, UART_INT_Type intType, BL_Mask_Type intMask) {
  uint32_t tmpVal;
  uint32_t UARTx = uartAddr[uartId];

  /* Check the parameters */
  CHECK_PARAM(IS_UART_ID_TYPE(uartId));
  CHECK_PARAM(IS_UART_INT_TYPE(intType));
  CHECK_PARAM(IS_BL_MASK_TYPE(intMask));

  tmpVal = BL_RD_REG(UARTx, UART_INT_MASK);

  /* Mask or unmask certain or all interrupt */
  if (UART_INT_ALL == intType) {
    if (MASK == intMask) {
      tmpVal |= 0x1ff;
    } else {
      tmpVal &= 0;
    }
  } else {
    if (MASK == intMask) {
      tmpVal |= 1 << intType;
    } else {
      tmpVal &= ~(1 << intType);
    }
  }

  /* Write back */
  BL_WR_REG(UARTx, UART_INT_MASK, tmpVal);

  return SUCCESS;
}

/****************************************************************************/ /**
                                                                                * @brief  UART clear certain or all interrupt
                                                                                *
                                                                                * @param  uartId: UART ID type
                                                                                * @param  intType: UART interrupt type
                                                                                *
                                                                                * @return SUCCESS
                                                                                *
                                                                                *******************************************************************************/
BL_Err_Type UART_IntClear(UART_ID_Type uartId, UART_INT_Type intType) {
  uint32_t tmpVal;
  uint32_t UARTx = uartAddr[uartId];

  /* Check the parameters */
  CHECK_PARAM(IS_UART_ID_TYPE(uartId));
  CHECK_PARAM(IS_UART_INT_TYPE(intType));

  tmpVal = BL_RD_REG(UARTx, UART_INT_CLEAR);

  /* Clear certain or all interrupt */
  if (UART_INT_ALL == intType) {
    tmpVal |= 0x1ff;
  } else {
    tmpVal |= 1 << intType;
  }

  /* Write back */
  BL_WR_REG(UARTx, UART_INT_CLEAR, tmpVal);

  return SUCCESS;
}

/****************************************************************************/ /**
                                                                                * @brief  Install uart interrupt callback function
                                                                                *
                                                                                * @param  uartId: UART ID type
                                                                                * @param  intType: UART interrupt type
                                                                                * @param  cbFun: Pointer to interrupt callback function. The type should be void (*fn)(void)
                                                                                *
                                                                                * @return SUCCESS
                                                                                *
                                                                                *******************************************************************************/
BL_Err_Type UART_Int_Callback_Install(UART_ID_Type uartId, UART_INT_Type intType, intCallback_Type *cbFun) {
  /* Check the parameters */
  CHECK_PARAM(IS_UART_ID_TYPE(uartId));
  CHECK_PARAM(IS_UART_INT_TYPE(intType));

  uartIntCbfArra[uartId][intType] = cbFun;

  return SUCCESS;
}

/****************************************************************************/ /**
                                                                                * @brief  UART send data to tx fifo
                                                                                *
                                                                                * @param  uartId: UART ID type
                                                                                * @param  data: The data to be send
                                                                                * @param  len: The length of the send buffer
                                                                                *
                                                                                * @return SUCCESS
                                                                                *
                                                                                *******************************************************************************/
BL_Err_Type UART_SendData(UART_ID_Type uartId, uint8_t *data, uint32_t len) {
  uint32_t txLen      = 0;
  uint32_t UARTx      = uartAddr[uartId];
  uint32_t timeoutCnt = UART_TX_TIMEOUT_COUNT;

  /* Check the parameter */
  CHECK_PARAM(IS_UART_ID_TYPE(uartId));

  /* Send data */
  while (txLen < len) {
    if (UART_GetTxFifoCount(uartId) > 0) {
      BL_WR_BYTE(UARTx + UART_FIFO_WDATA_OFFSET, data[txLen++]);
      timeoutCnt = UART_TX_TIMEOUT_COUNT;
    } else {
      timeoutCnt--;

      if (timeoutCnt == 0) {
        return TIMEOUT;
      }
    }
  }

  return SUCCESS;
}

/****************************************************************************/ /**
                                                                                * @brief  UART send data to tx fifo in block mode
                                                                                *
                                                                                * @param  uartId: UART ID type
                                                                                * @param  data: The data to be send
                                                                                * @param  len: The length of the send buffer
                                                                                *
                                                                                * @return SUCCESS
                                                                                *
                                                                                *******************************************************************************/
BL_Err_Type UART_SendDataBlock(UART_ID_Type uartId, uint8_t *data, uint32_t len) {
  uint32_t txLen      = 0;
  uint32_t UARTx      = uartAddr[uartId];
  uint32_t timeoutCnt = UART_TX_TIMEOUT_COUNT;

  /* Check the parameter */
  CHECK_PARAM(IS_UART_ID_TYPE(uartId));

  /* Send data */
  while (txLen < len) {
    if (UART_GetTxFifoCount(uartId) > 0) {
      BL_WR_BYTE(UARTx + UART_FIFO_WDATA_OFFSET, data[txLen++]);
      timeoutCnt = UART_TX_TIMEOUT_COUNT;
    } else {
      timeoutCnt--;

      if (timeoutCnt == 0) {
        return TIMEOUT;
      }
    }
  }

  while (UART_GetTxBusBusyStatus(uartId) == SET) {
  }

  return SUCCESS;
}

/****************************************************************************/ /**
                                                                                * @brief  UART receive data from rx fifo
                                                                                *
                                                                                * @param  uartId: UART ID type
                                                                                * @param  data: The receive data buffer
                                                                                * @param  maxLen: The max length of the buffer
                                                                                *
                                                                                * @return The length of the received buffer
                                                                                *
                                                                                *******************************************************************************/
uint32_t UART_ReceiveData(UART_ID_Type uartId, uint8_t *data, uint32_t maxLen) {
  uint32_t rxLen = 0;
  uint32_t UARTx = uartAddr[uartId];

  /* Check the parameter */
  CHECK_PARAM(IS_UART_ID_TYPE(uartId));

  /* Receive data */
  while (rxLen < maxLen && UART_GetRxFifoCount(uartId) > 0) {
    data[rxLen++] = BL_RD_BYTE(UARTx + UART_FIFO_RDATA_OFFSET);
  }

  return rxLen;
}

/****************************************************************************/ /**
                                                                                * @brief  UART get auto baud count value
                                                                                *
                                                                                * @param  uartId: UART ID type
                                                                                * @param  autoBaudDet: Detection using codeword 0x55 or start bit
                                                                                *
                                                                                * @return Bit period of auto baudrate detection
                                                                                *
                                                                                *******************************************************************************/
uint16_t UART_GetAutoBaudCount(UART_ID_Type uartId, UART_AutoBaudDetection_Type autoBaudDet) {
  uint32_t UARTx = uartAddr[uartId];

  /* Check the parameter */
  CHECK_PARAM(IS_UART_ID_TYPE(uartId));
  CHECK_PARAM(IS_UART_AUTOBAUDDETECTION_TYPE(autoBaudDet));

  /* Select 0x55 or start bit detection value */
  if (UART_AUTOBAUD_0X55 == autoBaudDet) {
    return BL_RD_REG(UARTx, UART_STS_URX_ABR_PRD) >> 0x10 & 0xffff;
  } else {
    return BL_RD_REG(UARTx, UART_STS_URX_ABR_PRD) & 0xffff;
  }
}

/****************************************************************************/ /**
                                                                                * @brief  UART get tx fifo unoccupied count value
                                                                                *
                                                                                * @param  uartId: UART ID type
                                                                                *
                                                                                * @return Tx fifo unoccupied count value
                                                                                *
                                                                                *******************************************************************************/
uint8_t UART_GetTxFifoCount(UART_ID_Type uartId) {
  uint32_t UARTx = uartAddr[uartId];

  /* Check the parameter */
  CHECK_PARAM(IS_UART_ID_TYPE(uartId));

  return BL_GET_REG_BITS_VAL(BL_RD_REG(UARTx, UART_FIFO_CONFIG_1), UART_TX_FIFO_CNT);
}

/****************************************************************************/ /**
                                                                                * @brief  UART get rx fifo occupied count value
                                                                                *
                                                                                * @param  uartId: UART ID type
                                                                                *
                                                                                * @return Rx fifo occupied count value
                                                                                *
                                                                                *******************************************************************************/
uint8_t UART_GetRxFifoCount(UART_ID_Type uartId) {
  uint32_t UARTx = uartAddr[uartId];

  /* Check the parameter */
  CHECK_PARAM(IS_UART_ID_TYPE(uartId));

  return BL_GET_REG_BITS_VAL(BL_RD_REG(UARTx, UART_FIFO_CONFIG_1), UART_RX_FIFO_CNT);
}

/****************************************************************************/ /**
                                                                                * @brief  Get uart interrupt status
                                                                                *
                                                                                * @param  uartId: UART ID type
                                                                                * @param  intType: UART interrupt type
                                                                                *
                                                                                * @return Status of interrupt
                                                                                *
                                                                                *******************************************************************************/
BL_Sts_Type UART_GetIntStatus(UART_ID_Type uartId, UART_INT_Type intType) {
  uint32_t tmpVal;
  uint32_t UARTx = uartAddr[uartId];

  /* Check the parameters */
  CHECK_PARAM(IS_UART_ID_TYPE(uartId));
  CHECK_PARAM(IS_UART_INT_TYPE(intType));

  /* Get certain or all interrupt status */
  tmpVal = BL_RD_REG(UARTx, UART_INT_STS);

  if (UART_INT_ALL == intType) {
    if ((tmpVal & 0x1ff) != 0) {
      return SET;
    } else {
      return RESET;
    }
  } else {
    if ((tmpVal & (1U << intType)) != 0) {
      return SET;
    } else {
      return RESET;
    }
  }
}

/****************************************************************************/ /**
                                                                                * @brief  Get indicator of uart tx bus busy
                                                                                *
                                                                                * @param  uartId: UART ID type
                                                                                *
                                                                                * @return Status of tx bus
                                                                                *
                                                                                *******************************************************************************/
BL_Sts_Type UART_GetTxBusBusyStatus(UART_ID_Type uartId) {
  uint32_t tmpVal;
  uint32_t UARTx = uartAddr[uartId];

  /* Check the parameters */
  CHECK_PARAM(IS_UART_ID_TYPE(uartId));

  /* Get tx bus busy status */
  tmpVal = BL_RD_REG(UARTx, UART_STATUS);

  if (BL_IS_REG_BIT_SET(tmpVal, UART_STS_UTX_BUS_BUSY)) {
    return SET;
  } else {
    return RESET;
  }
}

/****************************************************************************/ /**
                                                                                * @brief  Get indicator of uart rx bus busy
                                                                                *
                                                                                * @param  uartId: UART ID type
                                                                                *
                                                                                * @return Status of rx bus
                                                                                *
                                                                                *******************************************************************************/
BL_Sts_Type UART_GetRxBusBusyStatus(UART_ID_Type uartId) {
  uint32_t tmpVal;
  uint32_t UARTx = uartAddr[uartId];

  /* Check the parameters */
  CHECK_PARAM(IS_UART_ID_TYPE(uartId));

  /* Get rx bus busy status */
  tmpVal = BL_RD_REG(UARTx, UART_STATUS);

  if (BL_IS_REG_BIT_SET(tmpVal, UART_STS_URX_BUS_BUSY)) {
    return SET;
  } else {
    return RESET;
  }
}

/****************************************************************************/ /**
                                                                                * @brief  Get tx/rx fifo overflow or underflow status
                                                                                *
                                                                                * @param  uartId: UART ID type
                                                                                * @param  overflow: Select tx/rx overflow or underflow
                                                                                *
                                                                                * @return Status of tx/rx fifo
                                                                                *
                                                                                *******************************************************************************/
BL_Sts_Type UART_GetOverflowStatus(UART_ID_Type uartId, UART_Overflow_Type overflow) {
  uint32_t tmpVal;
  uint32_t UARTx = uartAddr[uartId];

  /* Check the parameters */
  CHECK_PARAM(IS_UART_ID_TYPE(uartId));
  CHECK_PARAM(IS_UART_OVERFLOW_TYPE(overflow));

  /* Get tx/rx fifo overflow or underflow status */
  tmpVal = BL_RD_REG(UARTx, UART_FIFO_CONFIG_0);

  if ((tmpVal & (1U << (overflow + 4))) != 0) {
    return SET;
  } else {
    return RESET;
  }
}

/****************************************************************************/ /**
                                                                                * @brief  UART0 interrupt handler
                                                                                *
                                                                                * @param  None
                                                                                *
                                                                                * @return None
                                                                                *
                                                                                *******************************************************************************/
#ifndef BFLB_USE_HAL_DRIVER
void UART0_IRQHandler(void) { UART_IntHandler(UART0_ID); }
#endif

/****************************************************************************/ /**
                                                                                * @brief  UART1 interrupt handler
                                                                                *
                                                                                * @param  None
                                                                                *
                                                                                * @return None
                                                                                *
                                                                                *******************************************************************************/
#ifndef BFLB_USE_HAL_DRIVER
void UART1_IRQHandler(void) { UART_IntHandler(UART1_ID); }
#endif

/*@} end of group UART_Public_Functions */

/*@} end of group UART */

/*@} end of group BL702_Peripheral_Driver */
